package com.rwb.reconciliation.utils;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.LineIterator;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Properties;

/**
 * @Auther: ruwenbo
 * @Date: 2018/9/22 14:08
 * @Description:
 */
public class FileUtil {

    // 日志组件
    private static final Logger logger = LoggerFactory.getLogger(FileUtil.class);

    // ftp配置信息路径
    private static final String FILE_CONF_LOCATION = "conf/fileParse.properties";

    // 下载到本地路径加yyyyMMdd文件夹
    private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");

    // 存放ftp信息properties
    private static Properties properties = new Properties();

    //--------------- FTP信息 start -----------------------
    private static String ftpHost, ftpPort, ftpUserName, ftpPassword, downloadPath, remotePath;
    //--------------- FTP信息 end -----------------------

    // FTP 客户端
    private static FTPClient ftpClient;

    static {
        try {
            InputStream inputStream = FileUtil.class.getClassLoader().getResourceAsStream(FILE_CONF_LOCATION);
            properties.load(inputStream);
            ftpHost = properties.getProperty("com.rwb.ftpHost");
            ftpPort = properties.getProperty("com.rwb.ftpPort");
            ftpUserName = properties.getProperty("com.rwb.ftpUserName");
            ftpPassword = properties.getProperty("com.rwb.ftpPassword");
            downloadPath = properties.getProperty("com.rwb.downloadPath");
            remotePath = properties.getProperty("com.rwb.remotePath");
        } catch (Exception e) {
            logger.error("================== load ftp properties err.", e);
        }
    }

    private FileUtil() {

    }

    /**
     * 下载FTP文件到本地
     *
     * @param downloadFileName 下载文件名
     * @param ftpPath          从ftp的哪个目录下载文件
     * @return 下载得到的文件
     */
    public static File downLoadFile(String downloadFileName, String ftpPath) {

        logger.info("============ FileUtil.downLoadFile下载FTP文件到本地 start ============");
        logger.info("============ 文件名:{}, ftp路径:{} ================", downloadFileName, ftpPath);

        if (StringUtils.isEmpty(downloadFileName)) {
            throw new IllegalArgumentException("入参为空");
        }

        File file = null;
        OutputStream outputStream;
        ftpPath = ftpPath == null ? remotePath : ftpPath;

        if (ftpClient == null) {
            ftpClient = new FTPClient();
        }

        try {
            // 1.连接ftp
            ftpClient.connect(ftpHost, Integer.parseInt(ftpPort));

            // 2. 登录ftp
            ftpClient.login(ftpUserName, ftpPassword);

            // 3.设置ftpClient相关信息
            prepareFtpClient(ftpClient);

            // 4. 判断是否连接成功
            if (!FTPReply.isPositiveCompletion(ftpClient.getReplyCode())) {
                throw new RuntimeException("ftp connection err.");
            }

            // 5.判断ftp是否存在该文件夹
            if (!ftpClient.changeWorkingDirectory(ftpPath)) {
                throw new RuntimeException("ftp server not found [" + ftpPath + "] directory.");
            }

            // 6.遍历该目录下所有文件与下载文件名进行匹配
            FTPFile[] ftpFiles = ftpClient.listFiles();
            for (FTPFile ftpFile : ftpFiles) {
                if (downloadFileName.equals(ftpFile.getName())) {
                    // 7. 将ftp文件复制到本地
                    file = new File(downloadPath + "/" + ftpFile.getName());
                    /*if (!file.exists()) {
                        file.mkdir();
                    }*/
                    outputStream = new FileOutputStream(file);
                    ftpClient.retrieveFile(ftpFile.getName(), outputStream);
                    break;
                }
            }

            // 8. 删除本地一周前文件夹
            deleteBeforeWeekDir();

            // 9.退出登录
            ftpClient.logout();
        } catch (Exception e) {
            logger.info("download file from ftp server err.", e);
            throw new RuntimeException("download file by ftp server err, fileName:[" + downloadFileName + "]");
        } finally {
            try {
                if (ftpClient.isConnected()) {
                    ftpClient.disconnect();
                }
            } catch (IOException e) {
                logger.error("disconnect ftpClient err.", e);
            }
        }

        logger.info("============ FileUtil.downLoadFile下载FTP文件到本地 end ============");
        return file;
    }

    /**
     * 将本地文件上传到FTP
     * @param file          上传的文件
     * @param ftpPath       上传到FTP的目录
     */
    public static boolean uploadFile(File file, String ftpPath) {

        logger.info("============ FileUtil.uploadFile上传本地文件到ftp服务器 start ============");
        logger.info("============ 文件名:{}, ftp路径:{} ================", file.getName(), ftpPath);

        if (file == null || StringUtils.isEmpty(ftpPath)) {
            throw new IllegalArgumentException("入参为空");
        }

        InputStream inputStream = null;
        try {
            if (ftpClient == null) {
                ftpClient = new FTPClient();
            }

            // 1. 连接ftp服务器
            ftpClient.connect(ftpHost, Integer.parseInt(ftpPort));

            // 2. 登录ftp服务器
            ftpClient.login(ftpUserName, ftpPassword);

            // 3. 准备FTPClient参数
            prepareFtpClient(ftpClient);

            // 4. 判断ftp是否连接成功
            if (!FTPReply.isPositiveCompletion(ftpClient.getReplyCode())) {
                throw new RuntimeException("connection ftp server err.");
            }

            // 5. 判断ftpPath在服务器是否存在, 不存在则创建
            checkFtpPath(ftpPath);

            // 6. 上传文件(二进制)
            ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
            inputStream = new FileInputStream(file);
            if (!ftpClient.storeFile(file.getName(), inputStream)) {
                logger.error("============== upload file to ftp server fail. =============");
                return false;
            }

            // 7. 退出ftp服务器
            ftpClient.logout();
            return true;
        } catch (Exception e) {
            logger.error("upload file to ftpServer err.");
            throw new RuntimeException("upload file to ftpServer err.", e);

        } finally {
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
                if (ftpClient.isConnected()) {
                    ftpClient.disconnect();
                }
            } catch (IOException e) {
                logger.warn("close inputStream or ftpClient err.", e);
            }
        }
    }

    /**
     * 解析文件为List<String>
     * @param file      需要解析的文件
     * @return
     */
    public static List<String> parseFile(File file) {

        List<String> fileContent = null;

        if (file == null) {
            return fileContent;
        }

        FileReader reader = null;
        try {
            reader = new FileReader(file);
            LineIterator iterator = new LineIterator(reader);
            while (iterator.hasNext()) {
                fileContent.add(iterator.next());
            }
        } catch (Exception e) {
            logger.error("============ 解析文件异常 ============", e);
        } finally {
            try {
                if (reader != null) {
                    reader.close();
                }
            } catch (IOException e) {
                logger.warn("close reader err.", e);
            }
        }
        return fileContent;
    }

    /**
     * 创建文件时校验文件夹在ftp是否存在, 不存在则创建
     * @param ftpPath
     * @throws IOException
     */
    private static void checkFtpPath(String ftpPath) throws IOException {
        if (!ftpClient.changeWorkingDirectory(ftpPath)) {
            String[] dirs = ftpPath.split("/");
            for (String dir : dirs) {
                if (StringUtils.isEmpty(dir)) {
                    continue;
                }
                // 判断ftp是否存在该节点目录
                if (!ftpClient.changeWorkingDirectory(dir)) {
                    // 不存在节点目录则创建
                    if (!ftpClient.makeDirectory(dir)) {
                        throw new RuntimeException("ftp server create dir err.");
                    }
                    // 跳转到新创建的目录.循环创建子目录
                    ftpClient.changeWorkingDirectory(dir);
                }
            }
        }
    }


    /**
     * ftp文件夹下载到本地后删除本地一周前的文件夹
     */
    private static void deleteBeforeWeekDir() {

        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.add(Calendar.DAY_OF_WEEK, -1);
        String weekBeforeDay = dateFormat.format(calendar.getTime());

        File baseDirFile = new File(downloadPath);
        File[] listFiles = baseDirFile.listFiles();
        try {
            for (File file : listFiles) {
                if (file.getName().compareTo(weekBeforeDay) < 0) {
                    FileUtils.deleteDirectory(file);
                }
            }
        } catch (IOException e) {
            logger.warn("=============== 删除一周前文件夹异常 ================", e);
        }

    }

    /**
     * 准备ftpClient参数
     * @param ftpClient
     * @throws IOException
     */
    private static void prepareFtpClient(FTPClient ftpClient) throws IOException {

        //设置文件编码格式
        ftpClient.setControlEncoding("UTF-8");
        //ftp通信有两种模式
        //PORT(主动模式)客户端开通一个新端口(>1024)并通过这个端口发送命令或传输数据,期间服务端只使用他开通的一个端口，例如21
        //PASV(被动模式)客户端向服务端发送一个PASV命令，服务端开启一个新端口(>1024),并使用这个端口与客户端的21端口传输数据
        //由于客户端不可控，防火墙等原因，所以需要由服务端开启端口，需要设置被动模式
        ftpClient.enterLocalPassiveMode();
        //设置传输方式为流方式
        ftpClient.setFileTransferMode(FTP.STREAM_TRANSFER_MODE);
    }



}
